
/* Patch.m	Peter Wickersham
 *
 * Methods for Patch class.
 *
 */
 
#import "../Stone3DAPI/Stone3D.h"

#import "Patch.h"
#import "../ControlPoint.bproj/ControlPoint.h"
#import <ri/ri.h>

#define X0 	-1.0
#define X1	-0.33
#define X2	 0.33
#define X3 	 1.0
#define Y0 	-0.7
#define Y1 	-0.1
#define Y2 	 0.1
#define Y3 	 0.7
#define Z0 	-1.0
#define Z1 	-0.33
#define Z2 	 0.33
#define Z3 	 1.0

#define BEZIER		0
#define HERMITE 	1
#define BSPLINE		2
#define CATMULLROM	3


@implementation Patch

// The init method has the same overall implications as it usually does in
// instance initialization with the added bonus of knowing that your shape
// will added into the worldShape hierarchy according to the actions of the
// user.  Therefore, you can create a small little hierarchy of your own with
// the knowledge that it be just fit right in.
// In Patch, I create the standard Patch shape the appears in The RenderMan
// Companion.
- init
{
    RtFloat	pts[16][3] =  {
		{ X0, Y0, Z0}, { X1, Y2, Z0}, { X2, Y1, Z0}, { X3, Y3, Z0},
		{ X0, Y1, Z1}, { X1, Y2, Z1}, { X2, Y1, Z1}, { X3, Y2, Z1},
		{ X0, Y1, Z2}, { X1, Y2, Z2}, { X2, Y1, Z2}, { X3, Y2, Z2},
		{ X0, Y0, Z3}, { X1, Y2, Z3}, { X2, Y1, Z3}, { X3, Y3, Z3}};
    id		temp, lastShape;
    int		i;
 
    // First I let Shape perform any inits that it might need to.
    [super init];
    
    // Then I create my List of control points, which are subclassed Shapes
    // as well, and give them their initial translations.  Finally I add them
    // in the hierarchy under Patch.  In order to set up the sub hierarchy
    // correctly, we need to add the first control point as a descendent of
    // self(Patch) and then add all subsequent point shape objects as peers
    // to the last added point.
    controlPts = [[List allocFromZone:[self zone]] initCount:16];
    temp = [[ControlPoint allocFromZone:[self zone]] init];
    [temp translateTo:pts[0][0] :pts[0][1] :pts[0][2]];
    [temp linkAncestor:self];
    [self linkDescendant:temp];
    [controlPts addObject:temp];
    for (i=1; i<16; i++) {
	lastShape = temp;
	temp = [[ControlPoint allocFromZone:[self zone]] init];
	[temp translateTo:pts[i][0] :pts[i][1] :pts[i][2]];
	[lastShape linkPeer:temp];
	[controlPts addObject:temp];
    }
    
    // Finally, I set the default basis matrices and step sizes.
    // The step sizes for a singular patch is always 3 and does not
    // really matter unless it is a mesh.
    uBasis = BEZIER; bcopy(&RiBezierBasis,&theUBasis,sizeof(RtBasis));
    vBasis = BEZIER; bcopy(&RiBezierBasis,&theVBasis,sizeof(RtBasis));
    uStep = 3;
    vStep = 3;
    showCtlPoints = YES;
    showHull = NO;
    
    // The X min and max
    boundingBox[0] = 999;  boundingBox[1] = -999;
    
    // The Y min and max
    boundingBox[2] = 999;  boundingBox[3] = -999;
    
    // The Z min and max
    boundingBox[4] = 999;  boundingBox[5] = -999;
    
    return self;
}


// The following methods are for querying and setting various instance
// variables.  These variables are generally going to be accessed through
// an inspector panel that is installed concurrently with this class by
// the 3DReality class management facilities.  Therefore, if you want to 
// allow the user to set characteristics of your shape, then you must provide
// an inspector of the name <shapeClassName>Inspector with interface objects
// for tweaking parameters.

- (BOOL) hullVisible
{
    return showHull;
}

- setHullVisible:(BOOL) flag
{
    showHull = flag;
    return self;
}

- (BOOL)controlVisible
{
    return showCtlPoints;
}

- setControlVisible:(BOOL)flag
{
    int		i, max;
    id   	*clist;
    
    showCtlPoints = flag;
    for (i=0, max = [controlPts count],
	clist=NX_ADDRESS(controlPts);i<max;i++) {
	    [clist[i] setVisible:flag];
	}
    return self;
}

- (int)uBasis
{
    return uBasis;
}

- setUBasis:(int)theU
{
    uBasis = theU;
    switch (uBasis) {
	case BEZIER: bcopy(&RiBezierBasis,&theUBasis,sizeof(RtBasis));
		     break;
	case HERMITE: bcopy(&RiHermiteBasis,&theUBasis,sizeof(RtBasis));
		     break;
	case BSPLINE: bcopy(&RiBSplineBasis,&theUBasis,sizeof(RtBasis));
		     break;
	case CATMULLROM: bcopy(&RiCatmullRomBasis,&theUBasis,sizeof(RtBasis));
		     break;
	default: bcopy(&RiBezierBasis,&theUBasis,sizeof(RtBasis));
    }
    return self;
}

- (int)vBasis 
{
    return vBasis;
}

- setVBasis:(int)theV
{
    vBasis = theV;
    switch (vBasis) {
	case BEZIER: bcopy(&RiBezierBasis,&theVBasis,sizeof(RtBasis));
		     break;
	case HERMITE: bcopy(&RiHermiteBasis,&theVBasis,sizeof(RtBasis));
		     break;
	case BSPLINE: bcopy(&RiBSplineBasis,&theVBasis,sizeof(RtBasis));
		     break;
	case CATMULLROM: bcopy(&RiCatmullRomBasis,&theVBasis,sizeof(RtBasis));
		     break;
	default: bcopy(&RiBezierBasis,&theVBasis,sizeof(RtBasis));
    }
    return self;
}


// In order to provide selection capablity we must override Shapes instance 
// method calcBoundingBox.
- calcBoundingBox
{
    int		i, max;		// index variables
    id   	*clist;		// Address of control point list
    RtFloat 	pt[3];
    
    for (i=0, max = [controlPts count],
	clist=NX_ADDRESS(controlPts);i<max;i++) {
	    [clist[i] trans:&pt[0]];
	    if (pt[0] < boundingBox[0]) boundingBox[0] = pt[0];
	    if (pt[0] > boundingBox[1]) boundingBox[1] = pt[0];
	    if (pt[1] < boundingBox[2]) boundingBox[2] = pt[1];
	    if (pt[1] > boundingBox[3]) boundingBox[3] = pt[1];
	    if (pt[2] < boundingBox[4]) boundingBox[4] = pt[2];
	    if (pt[2] > boundingBox[5]) boundingBox[5] = pt[2];
    }
    return self;
}


// doRenderSelf is the method where the rendering code is placed.  Here we
// just make normal RenderMan function calls for creating RIB code that gets
// interpreted by either QRMAN or PRMAN depending on whether we are printing
// or drawing the RIB code.  
- doRenderSelf: (Camera *) camera
{
    int		i, max;		// index variables
    id   	*clist;		// Address of control point list
    RtFloat	tmppts[16][3];	// The current position of the control points
    
    // verts and nverst are for passing the vertex info to RiPointsPolygon
    // for the control hull.
    static RtInt verts[32] = {0,1,5,4,4,5,9,8,8,9,13,12,13,14,10,6,2,1,5,9,
			      2,3,7,6,6,7,11,10,14,15,11,10};
    static RtInt nverts[7] = {4,4,4,8,4,4,4};

    // First let our superclass Shape do its rendering code.  This could 
    // include shading and texturing calls.
    [super doRenderSelf:camera];
    
    // Then we get the current translation information from the control 
    // points.  This gives us their current positions in the Patch space.
    for (i=0, max = [controlPts count],
	clist=NX_ADDRESS(controlPts);i<max;i++) {
	    [clist[i] trans:&tmppts[i][0]];
	}
    
    // Draw the control hull polygon if needed using RiPointsPolygon
    if (showHull) {
	RiPointsPolygons((RtInt)7,nverts,verts,RI_P,(RtPointer)tmppts,RI_NULL);
    }
    
    // Set the U and V basis matrices and then draw the patch using 
    // RiPatch with the translations of the control points.
    RiBasis(theUBasis, (RtInt)uStep, theVBasis, (RtInt)vStep);
    RiPatch(RI_BICUBIC, RI_P, (RtPointer)tmppts, RI_NULL);
    
    return self;
}
@end
	